package visualization;



import infovis07contest.data.Genre;
import infovis07contest.data.Movie;
import infovis07contest.data.MovieDB;
import infovis07contest.data.Oscar;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;

import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PImage;



public class Launcher extends PApplet {



	int 	histo_width = 1000;
	int 	window_width = histo_width + 400;
	int 	histo_height = 610;
	int 	window_height = histo_height + 150;
	int		textMargin = 10;
	int 	textFill = 80;
	int 	textFillDark = 0;
	int 	shrinkedColumnWidth = 0;
	int		shrinkedRowHeight = 0;
	int		overGenreLabel = -1;
	int		overYearLabel = -1;
	int		genreButtonCount = 0;
	int		yearButtonCount = 0;

	public PFont 	font;
	PImage 	heartPref;

	
	// visibility of each row
	boolean[] rowVisibility = new boolean[21];
	boolean[] columnVisibility = new boolean[7];
	
	// this block loads the data from a text file
	int[][] count = new int[21][7];
	int count_MAX = -1;
	long[][] boxOfficeEarnings = new long[21][7];
	// the best box office earning of a genre for a particular year considering the whole table
	long boxOfficeEarnings_MAX = -1;
	int [][] ratings_cumul = new int[21][7];
	int [][] ratings_nb = new int[21][7];
	float[][] ratings = new float[21][7];
	float ratings_MAX = -1;
	float ratings_MIN = 32000;
	
	ZoomWindow zwindow;
	
	int buttonWidth = 100;
	int buttonHeight = 25;
	
	int lockX = -1;
	int lockY = -1;
	
	HistoCell[][] histo = new HistoCell[21][7]; 
	int[][][] prefs = new int[21][7][4];		// for each cell, how many unseen, seen and like, seen and don't care, seeen and dislike 
	LabelButton[] genreButtons = new LabelButton[21];
	LabelButton[] yearButtons = new LabelButton[7];
	
	Movie ordered[][][] = new Movie[21][7][]; 

	public static Movie sorted[][][] = new Movie[21][7][]; 
	
	public static int rowlength[][] = new int[21][7];
	
	public static int movieCount[][] = new int[21][7];
	
	public static int rc[][][] = new int[21][7][];
	
	public static int gc[][][] = new int[21][7][];
	
	public static int bc[][][] = new int[21][7][];
	
	public static int ci[][][] = new int[21][7][];
	
	public static int[][] cs = new int[4][];
	
	public static PFont f16;
	public static PFont d14;
	
	public static PImage left;
	public static PImage top;
	
	public void setup() {
		
		int[] c0 = {0,128,227};
		int[] c1 = {123,239,7};
		int[] c2 = {70,136,4};
		int[] c3 = {225,13,13};
		cs[0] = c0;
		cs[1] = c1;
		cs[2] = c2;
		cs[3] = c3;
		size(window_width,window_height);
		
		System.out.println("Parsing serializable data...");
		// uncomment the following line to get load the data from the data set
		MovieDB.readSerializedFile("data/moviedb2.serialized");
		orderMovies();
		
		left = loadImage("data/label_left.png");
		top = loadImage("data/label_top.png");
		
		zwindow = new ZoomWindow(histo_width, 0, 0, 2001, window_width-histo_width, 200);
		
		
		// loads data from a textfile
		try {
			Scanner scan = new Scanner(new File("data/boxOfficeEarnings.data")).useDelimiter(",");
			
			for (int i = 0; i < 21; i ++) {
				for (int j = 0; j < 7; j++) {
					boxOfficeEarnings[i][j] = scan.nextLong();
				}
				scan.nextLine();
			}

		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
		
		
		
		try {
			Scanner scan = new Scanner(new File("data/moviecount.data")).useDelimiter(",");
			
			for (int i = 0; i < 21; i ++) {
				for (int j = 0; j < 7; j++) {
					count[i][j] = scan.nextInt();
				}
				scan.nextLine();
			}
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
		
		
		
		try {
			Scanner scan = new Scanner(new File("data/imdbRating.data")).useDelimiter(",");
			
			// ratings cumul
			for (int i = 0; i < 21; i ++) {
				for (int j = 0; j < 7; j++) {
					ratings_cumul[i][j] = scan.nextInt();
				}
				scan.nextLine();
			}
			
			// number of votes
			for (int i = 0; i < 21; i ++) {
				for (int j = 0; j < 7; j++) {
					ratings_nb[i][j] = scan.nextInt();
				}
				scan.nextLine();
			}
			
			// we divide both to average
			for (int i = 0; i < 21; i ++) {
				for (int j = 0; j < 7; j++) {
					ratings[i][j] = (float)ratings_cumul[i][j] / (float)ratings_nb[i][j];
				}
			}
			
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
		
		
		try {
			Scanner scan = new Scanner(new File("data/preferences.data")).useDelimiter(",");
			
			for (int i = 0; i < 21; i ++) {
				for (int j = 0; j < 7; j++) {
					for (int k = 0; k < 4; k++)
					{
						prefs[i][j][k] = scan.nextInt();
						//System.out.println(i + "       " + j + "    " + k + "  =   " + prefs[i][j][k]);
					}
				}
				scan.nextLine();
			}
		} catch (IOException ioe) {
			ioe.printStackTrace();
			
		}

		
		System.out.println("Parsing serializable data...");
			
	/*

		//Counting all different directors
		//Iterator<myPerson> iter = myMovieDB.instance.persons.values().iterator();
		Iterator<Movie> iter = MovieDB.instance.movies.values().iterator();
		

			Movie m = iter.next();


			if(m.genres.contains(Genre.action)) {
				count[0][m.year-2000]++;
				ratings[0][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.adult)) {
				count[1][m.year-2000]++;
				ratings[1][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.adventure)) {
				count[2][m.year-2000]++;
				ratings[2][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.animation)) {
				count[3][m.year-2000]++;
				ratings[3][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.comedy)) {
				count[4][m.year-2000]++;
				ratings[4][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.crime)) {
				count[5][m.year-2000]++;
				ratings[5][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.documentary)) {
				count[6][m.year-2000]++;
				ratings[6][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.drama)) {
				count[7][m.year-2000]++;
				ratings[7][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.family)) {
				count[8][m.year-2000]++;
				ratings[8][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.fantasy)) {
				count[9][m.year-2000]++;
				ratings[9][m.year-2000] += m.imdbRating;
			} 

	  		if (m.genres.contains(Genre.filmnoir)) {
				count[10][m.year-2000]++;
				ratings[10][m.year-2000] += m.imdbRating;
			}
	
			if (m.genres.contains(Genre.horror)) {
				count[11][m.year-2000]++;
				ratings[11][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.musical)) {
				count[12][m.year-2000]++;
				ratings[12][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.mystery)) {
				count[13][m.year-2000]++;
				ratings[13][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.romance)) {
				count[14][m.year-2000]++;
				ratings[14][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.scifi)) {
				count[15][m.year-2000]++;
				ratings[15][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.shortfilm)) {
				count[16][m.year-2000]++;
				ratings[16][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.thriller)) {
				count[17][m.year-2000]++;
				ratings[17][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.war)) {
				count[18][m.year-2000]++;
				ratings[18][m.year-2000] += m.imdbRating;
			} 
			if (m.genres.contains(Genre.western)) {
				count[19][m.year-2000]++;
				ratings[19][m.year-2000] += m.imdbRating;
			}
			if (m.genres.size() == 0) {
			//	System.out.println("NO GENRE");
				count[20][m.year-2000]++;
				ratings[20][m.year-2000] += m.imdbRating;
			}
			
		}
		
/*
		 
		// print out the information you want for debugging
		// just change the name of the array
		for (int i = 0; i < 21; i++) {
			for (int j = 0; j < 7; j++) {
				print(ratings[i][j]);
				if (j != 6 ) print(",");
			}
			println();
		}
		
	
*/

		// let's compute this maximum values
		for (int i = 0; i < 21; i++) {
			for (int j = 0; j < 7; j++) {
				if (boxOfficeEarnings[i][j] > boxOfficeEarnings_MAX)
					boxOfficeEarnings_MAX = boxOfficeEarnings[i][j];
				
				if (count[i][j] > count_MAX)
					count_MAX = count[i][j];
				
				if (ratings[i][j] > ratings_MAX)
					ratings_MAX = ratings[i][j];
				
				if ((rowVisibility[i]) && (columnVisibility[j])
						&& (ratings[i][j] < ratings_MIN))
					ratings_MIN = ratings[i][j];
			}
		}
		
		
		// all rows visible when the application starts
		for (int i = 0; i < 21; i++)
			rowVisibility[i] = true;
		
		for (int j = 0; j < 7; j++)
			columnVisibility[j] = true;
		
	
	  f16 = loadFont("data/Futura-Medium-16.vlw");
	  d14 = loadFont("data/DFKaiShu-SB-Estd-BF-14.vlw");

	
		// create cell objects
		for (int i = 0; i < 21; i++) {
			for (int j = 0; j < 7; j++) {

				histo[i][j] = new HistoCell((j + 1)*(histo_width / 8), i*(histo_height / 21), histo_width / 8, histo_height / 21, i, j,
											(float)count[i][j] / (float)count_MAX, (float)boxOfficeEarnings[i][j] / (float)boxOfficeEarnings_MAX,
											(float)(ratings[i][j] - ratings_MIN) / (float)(ratings_MAX - ratings_MIN),false);
				
				histo[i][j].displayBoxOffice(false);
				histo[i][j].displayCount(true);
				histo[i][j].displayRatings(false);
				histo[i][j].elementDisplayed = 1;

			}
		}
		


		

		
		// create buttons
		for (int i = 0; i < 21; i++)
			if (i < 20)

				genreButtons[i] = new LabelButton(buttonWidth + 6, histo_height - buttonHeight - 6 ,buttonWidth,buttonHeight, (Genre.values())[i].toString() );

			else

				genreButtons[i] = new LabelButton(buttonWidth + 6, histo_height - buttonHeight - 6 ,buttonWidth,buttonHeight, "unknown" );


		
		for (int i = 0; i < 7; i++)

			yearButtons[i] = new LabelButton(histo_width - buttonWidth - 6, 6 ,buttonWidth, buttonHeight, String.valueOf(2000 + i) );



		heartPref = loadImage("data/heart2.png");

		
	}

	
	
	
	// update the data in the cells according the visibility of the different lines and columns
	// an invisible item won't be considered in the computation (they are all visible at start-up)
	public void updateRatio()
	{
		boxOfficeEarnings_MAX = 0;
		count_MAX = 0;
		ratings_MAX = 0;
		ratings_MIN = 32000;
		
		// let's compute this maximum and minimun values AMONGST THE VISIBLE ITEMS
		for (int i = 0; i < 21; i++) {
			for (int j = 0; j < 7; j++) {
				if ((rowVisibility[i]) && (columnVisibility[j])
					&& (boxOfficeEarnings[i][j] > boxOfficeEarnings_MAX))
					boxOfficeEarnings_MAX = boxOfficeEarnings[i][j];
				
				if ((rowVisibility[i]) && (columnVisibility[j])
						&& (count[i][j] > count_MAX))
							count_MAX = count[i][j];
				
				
				if ((rowVisibility[i]) && (columnVisibility[j])
						&& (ratings[i][j] > ratings_MAX))
					ratings_MAX = ratings[i][j];
				
				if ((rowVisibility[i]) && (columnVisibility[j])
						&& (ratings[i][j] < ratings_MIN))
					ratings_MIN = ratings[i][j];
				
			}
		}
		
		for (int i = 0; i < 21; i++) {
			for (int j = 0; j < 7; j++) {
				histo[i][j].ratio_boxOfficeEarnings = (float)boxOfficeEarnings[i][j] / (float)boxOfficeEarnings_MAX;
				histo[i][j].ratio_movieCount = (float)count[i][j] / (float)count_MAX;
				histo[i][j].ratio_ratings = (float)(ratings[i][j] - ratings_MIN) / (float)(ratings_MAX - ratings_MIN);
				//System.out.println(histo[i][j].ratio_ratings);
			}
		}
	}
	
	
	
	public void draw() {
		//noLoop();
		
		  // Set the font and its size (in units of pixels)
		  textFont(f16);
		  
		int incHeight = 0;
		int incWidth = histo_width / 8;
		boolean display_save1 = false, display_save2 = false, display_save3 = false;
		int display_item = 0;

			
		fill(180,180,180);							// background color
		noStroke();
		rect(0,0,window_width,window_height);

		
		// small window on the right
		zwindow.draw(this);
		
		// Set the font and its size (in units of pixels)
	    textFont(f16, 16);

		overGenreLabel = -1;
		overYearLabel = -1;
		
		if (mouseX >= histo_width) {
			zwindow.findBoxUnderMouse(mouseX-histo_width, mouseY);
		}
		
		// check the mouse over event for the cells
		for (int i = 0; i < 21; i++) {

			for (int j = 0; j < 7; j++) {		
					display_save1 = histo[i][j].isBoxOfficeDisplayed();
					display_save2 = histo[i][j].isCountDisplayed();
					display_save3 = histo[i][j].isRatingsDisplayed();
					display_item = histo[i][j].elementDisplayed;
					
					histo[i][j] = new HistoCell((j + 1)*(histo_width / 8), i*(histo_height / 21), histo_width / 8, histo_height / 21,  i, j,
												(float)count[i][j] / (float)count_MAX, (float)boxOfficeEarnings[i][j] / (float)boxOfficeEarnings_MAX,
												(float)(ratings[i][j] - ratings_MIN) / (float)(ratings_MAX - ratings_MIN), mouseOver(i,j));
					histo[i][j].elementDisplayed = 0;
					
					histo[i][j].displayBoxOffice(display_save1);
					histo[i][j].displayCount(display_save2);
					histo[i][j].displayRatings(display_save3);
					histo[i][j].elementDisplayed = display_item;

			}
		}
		
		
		updateColumnWidth();
		updateRowHeight();

		// mouse even for genre labels (different computation)
		for (int i = 0; i < 21; i++) {
			if (mouseOver(i, -1))
				overGenreLabel = i;		// we over the label i
		}
		
		// if we have a genre selected, let's compute it
		if (overGenreLabel != -1)
			updateGenre(overGenreLabel);
		
		// mouse even for year labels (different computation)
		for (int i = 0; i < 7; i++) {
			if (mouseOver(-1, i))
				overYearLabel = i;		// we over the year label at column i
		}
		
		
		// if we have a year selected, let's compute it
		if (overYearLabel != -1)
			updateYear(overYearLabel);
		
		
		// preferences display
		int rowButton = (mouseY - histo_height) / (((window_height - histo_height) - 35) / 3);
		int colButton = (mouseX / (int)((float)histo_width / (float)25))+1;
		
		// we are overing the preference heart, let's darken the cells
		if ((rowButton == 3) && (colButton == 25))
		{
			
			for (int i = 0; i < 21; i++)      
				for (int j = 0; j < 7; j++)
				{	// we remove the bars as well, all the ratio down to 0
					histo[i][j].ratio_boxOfficeEarnings = 0;
					histo[i][j].ratio_movieCount = 0;
					histo[i][j].ratio_ratings = 0;
					histo[i][j].mouseOver = true;
				}		
		}
		
		
		// a locked cell?
		if ((lockX != -1) && (lockY != -1))
		{
			histo[lockX][lockY].mouseOver = true;
		}
		
		
		// we draw everything
		
		for (int i = 0; i < 22; i++) {
			
			incWidth = histo_width / 8;
			
			for (int j = 0; j < 8; j++) {
				
				
				if ((j == 0) && (i != 21))					// genre labels
				{
					if (overGenreLabel == i) fill(textFillDark); else  fill(textFill);
					// valide genres

					if (rowVisibility[i])
						if (i == 20)
							text("Unknown", textMargin, incHeight + (int)(getCurrentRowHeight() * 0.7) );
						else
							text((Genre.values())[i].toString(), textMargin, incHeight + (int)(getCurrentRowHeight() * 0.7));

				}
				else if ((i == 21) && (j != 7))				// year labels
				{
					if (overYearLabel == j) fill(textFillDark);  else  fill(textFill);

					//text(String.valueOf(2000 + j) , (window_width / 8) + (125 * j) + 50, incHeight + 30);
					
					if (columnVisibility[j])
						if (j != 0)
							text(String.valueOf(2000 + j) , incWidth + histo[0][j-1].w + 50, incHeight + 30);
						else
							text(String.valueOf(2000 + j) , incWidth + 50, incHeight + 30);

				}
				else if ((i!= 21))							// all the other cells
				{
					histo[i][j-1].y = incHeight;
					histo[i][j-1].x = incWidth;
					
					if (rowVisibility[i])
					{
						if (!columnVisibility[j-1])
							histo[i][j-1].w = shrinkedColumnWidth;
							
						histo[i][j-1].draw(this);
					}
					else
					{
						if (!columnVisibility[j-1])
							histo[i][j-1].w = shrinkedColumnWidth;
						
						histo[i][j-1].h = shrinkedRowHeight;
						histo[i][j-1].draw(this);
					}
						
				}
				
				if (j !=0 ) incWidth += histo[0][j-1].w;
				
			}
			
			// we have to relocate following rows if the current one was shrinked
			if (i != 21) incHeight += histo[i][0].h;
		}
		

		line(0,0,window_width,0);
	
		image(heartPref, histo_width - 30, histo_height + (3 * buttonHeight) + 35);
		
	    		  
		drawGenreButtons();
		drawYearButtons();

		drawToggleButtons();
		
		// we are overing the preference heart, let's darken the cells
		if ((rowButton == 3) && (colButton == 25))  
		{
			// display the numbers
			drawPreferences();
			
			// we changed all the ratio to 0, let's put them back to normal
			for (int i = 0; i < 21; i++) {
				for (int j = 0; j < 7; j++) {	
					histo[i][j].elementDisplayed = 0;
					histo[i][j].displayBoxOffice(display_save1);
					histo[i][j].displayCount(display_save2);
					histo[i][j].displayRatings(display_save3);
					histo[i][j].elementDisplayed = display_item;
				}
			}
		}
		
	}
	
	
	/**********************
	 * if Xcell != -1 and Ycell != -1
	 * 	
	 *		return true if the mouse is over the cell at (Xcell, Ycell), false otherwises
	 *
	 *	if Xcell == -1
	 *	
	 *		return true if the mouse is over any cell in the Ycell column
	 *
	 *	if Ycell == -1
	 *	
	 *		return true if the mouse is over any cell in the Xcell row
	 *
	 */
	
	public boolean mouseOver(int Xcell, int Ycell)
	{

		int incHeight = 0;
		int incWidth = histo_width / 8;		// first column for labels
		int selectedRow = -1;
		int selectedColumn = -1;
		
		if (mouseX > 500) selectedColumn = 100; else selectedColumn = -1;
		if (mouseY > (histo_height + (histo_height / 21))) selectedRow = 100; else selectedRow = -1;
		
			
		for (int i = 0; i < 21; i++) {
			if (rowVisibility[i])
			{
				if ((mouseY > incHeight) && (mouseY < incHeight + getCurrentRowHeight()))
					selectedRow = i;
					incHeight = incHeight + getCurrentRowHeight();
			}

			else
			{
				if ((mouseY > incHeight) && (mouseY < incHeight + shrinkedRowHeight))
					selectedRow = i;
					incHeight = incHeight + shrinkedRowHeight;
			}
		}
		
		for (int i = 0; i < 7; i++) {
			if ((columnVisibility[i]))
			{
				if ((mouseX > incWidth) && (mouseX < incWidth + getCurrentColumnWidth()))
					selectedColumn = i;
					incWidth = incWidth + getCurrentColumnWidth();
			}
			else
			{
				if ((mouseX > incWidth) && (mouseX < incWidth + shrinkedRowHeight))
					selectedColumn = i;
					incWidth = incWidth + shrinkedColumnWidth;
			}
		}
		
		
		if ((selectedColumn == Ycell ) && (selectedRow == Xcell))
			return true;
		else
			return false;

	}
	
	
	
	// when a mouse button is pressed
	public void mousePressed()
	{
		
		// ====  click on a cell???
		for (int i = 0; i < 21; i++) {
			for (int j = 0; j < 7; j++) {
				if(mouseOver(i,j))
				{
					lockX = i;
					lockY = j;
					zwindow.setDrawText( true);
				}
			}
		}
		
		
		// ====  click on a genre label???
		
		if ((overGenreLabel != -1) && (mouseButton == LEFT))
		{
			// we have to shrink that row (no more than 18 so we leave at least 2 of them)
			if (genreButtonPressed() < 18) rowVisibility[overGenreLabel] = false;
			// compute new ratios
			updateRatio();
		
		}
		
		
		// ====  click on a year label???
		
		if ((overYearLabel != -1) && (mouseButton == LEFT))
		{
			// we have to shrink that row (no more than 18 so we leave at least 2 of them)
			if (yearButtonPressed() < 6) columnVisibility[overYearLabel] = false;
			// compute new ratios
			updateRatio();
			updateColumnWidth();
		}
		
		
		// ====  click on a genre button???
		
		int rowButton = (mouseY - histo_height) / (((window_height - histo_height) - 35) / 3);
		int colButton = (mouseX / (int)((float)histo_width / (float)9.25))+1;
		
		// we are not on a cell, we might be on a button
		if ((mouseY > histo_height + 50) && (mouseX < histo_width))
		{
			// what button are we overing?
						
			if ((rowButton == 1) || (rowButton == 2))				// 1st or 2nd row
			{
			
				int row_dec = ((rowButton - 1) * 9) + colButton;
				int row_final = 0;
				
				do		// we look for the good genre
				{
					if (!rowVisibility[row_final]) 
						row_dec--;
					
					row_final++;
				}while((row_dec != 0) && (row_final < 21));
				
				// we have found which column it is, let's turn it visible
				if (row_final < 21) rowVisibility[row_final - 1] = true;
				// compute new ratios
				updateRatio();
				
			}
			
			
			
			if ((rowButton == 3) && (colButton <= 7))		// 3rd row
			{
				int col_dec = colButton, col_final = 0;
				
				do		// we look for the good year
				{
					if (!columnVisibility[col_final]) 
						col_dec--;
					
					col_final++;
				}while((col_dec != 0)  && (col_final < 7));
				
				// we have found which column it is, let's turn it visible
				if (col_final < 7)  columnVisibility[col_final - 1] = true;
				// compute new ratios
				updateRatio();
			}

			
			
			// ====  click on a toggle button???
			
			if ((rowButton == 3) && (colButton == 7))			// earnings button
			{
				for (int i = 0; i < 21; i++)
					for (int j = 0; j < 7; j++)
						histo[i][j].displayBoxOffice(!histo[i][j].isBoxOfficeDisplayed());
	
			}
			else if ((rowButton == 3) && (colButton == 8))		// count button
			{
				for (int i = 0; i < 21; i++)
					for (int j = 0; j < 7; j++)
						histo[i][j].displayCount(!histo[i][j].isCountDisplayed());
			}
			else if ((rowButton == 3) && (colButton == 9))		// ratings button
			{
				for (int i = 0; i < 21; i++)
					for (int j = 0; j < 7; j++)
						histo[i][j].displayRatings(!histo[i][j].isRatingsDisplayed());
			}
		}

	}
	
	public void mouseClicked() {
		if (mouseX >= histo_width) {
			//zwindow.findBoxUnderMouse(mouseX - histo_width, mouseY);
			zwindow.clickUnderMouse(mouseX - histo_width, mouseY);
			
			

		} else {
			int iOver=0;
			int jOver=0;
			for (int i = 0; i < 21; i++) {
				for (int j = 0; j < 7; j++) {
					if (mouseOver(i,j)) {
						iOver = i;
						jOver = j;
					}

				}
			}
			zwindow.setG(iOver);
			zwindow.setYrIndex(jOver);
		//	zwindow.update();
		}
	}
	
	
	
	public void updateGenre(int genre)
	{
		// we calculate the new max
		float localEarningsMaxValue = -1;
		float localCountMaxValue = -1;
		float localRatingsMaxValue = -1;
		
		for (int i = 0; i < 7; i++)
		{
			if ((histo[genre][i].ratio_boxOfficeEarnings > localEarningsMaxValue) && (columnVisibility[i]))
				localEarningsMaxValue = histo[genre][i].ratio_boxOfficeEarnings;	// we store the max ratio
			
			if ((histo[genre][i].ratio_movieCount > localCountMaxValue) && (columnVisibility[i]))
				localCountMaxValue = histo[genre][i].ratio_movieCount;	// we store the max ratio
			
			if ((histo[genre][i].ratio_ratings > localRatingsMaxValue) && (columnVisibility[i]))
				localRatingsMaxValue = histo[genre][i].ratio_ratings;	// we store the max ratio
		}
		
		// we gray out all the other cells
		for (int i = 0; i < 21; i++) {
			for (int j = 0; j < 7; j++) {
				histo[i][j].mouseOver = true;
			}
		}
		
		
		// we recompute all the data
		for (int i = 0; i < 7; i++)
		{	
			histo[genre][i].mouseOver = false;		// we light up these cells
			histo[genre][i].ratio_boxOfficeEarnings = (float)histo[genre][i].ratio_boxOfficeEarnings / (float)localEarningsMaxValue;
			histo[genre][i].ratio_movieCount = (float)histo[genre][i].ratio_movieCount / (float)localCountMaxValue;
			histo[genre][i].ratio_ratings = (float)histo[genre][i].ratio_ratings / (float)localRatingsMaxValue;
		}
		
		
	}
	
	
	
	public void updateYear(int year)
	{
		// we calculate the new max
		float localEarningsMaxValue = -1;
		float localCountMaxValue = -1;
		float localRatingsMaxValue = -1;
		
		for (int i = 0; i < 21; i++)
		{
			if ((histo[i][year].ratio_boxOfficeEarnings > localEarningsMaxValue) && (rowVisibility[i]))
				localEarningsMaxValue = histo[i][year].ratio_boxOfficeEarnings;	// we store the max ratio
			
			if ((histo[i][year].ratio_movieCount > localCountMaxValue) && (rowVisibility[i]))
				localCountMaxValue = histo[i][year].ratio_movieCount;	// we store the max ratio
			
			if ((histo[i][year].ratio_ratings > localRatingsMaxValue) && (rowVisibility[i]))
				localRatingsMaxValue = histo[i][year].ratio_ratings;	// we store the max ratio
		}
		
		
		// we gray out all the other cells
		for (int i = 0; i < 21; i++) {
			for (int j = 0; j < 7; j++) {
				histo[i][j].mouseOver = true;
			}
		}
		
		
		// we recompute all the data
		for (int i = 0; i < 21; i++)
		{	
			histo[i][year].mouseOver = false;		// we light up these cells
			
			histo[i][year].ratio_boxOfficeEarnings = (float)histo[i][year].ratio_boxOfficeEarnings / (float)localEarningsMaxValue;
			histo[i][year].ratio_movieCount = (float)histo[i][year].ratio_movieCount / (float)localCountMaxValue;
			histo[i][year].ratio_ratings = (float)histo[i][year].ratio_ratings / (float)localRatingsMaxValue;
		}
		
	}

	
	
	// when a column gets shrinked, the table is expended
	public void updateColumnWidth()
	{
		int remainingCol = 7 - yearButtonPressed();	// without the labels
		
		// the label column doesn't expend
		for (int i = 0; i < 21; i++)      
			for (int j = 0; j < 7; j++)
				if (columnVisibility[j])
					histo[i][j].w = (histo_width - (histo_width / 8)) / remainingCol;	

	}
	
	
	
	// when a rows gets shrinked, the table is expended
	public void updateRowHeight()
	{
		int remainingRow = 21 - genreButtonPressed();	// without the labels
		
		// the label year doesn't expend
		for (int i = 0; i < 21; i++)      
			for (int j = 0; j < 7; j++)
				if (rowVisibility[i])
					histo[i][j].h = histo_height / remainingRow;	

	}
	
	
	
	public int getCurrentColumnWidth()
	{
		return ((histo_width - (histo_width / 8)) / (7 - yearButtonPressed()));
	}
	
	
	public int getCurrentRowHeight()
	{
		return ((histo_height / (21 - genreButtonPressed())));
	}
	
	public void drawGenreButtons()
	{
		
		font = loadFont("data/Ziggurat-HTF-Black-32.vlw");

		// Set the font and its size (in units of pixels)
		
		int xcounter = 0;
		int buttonRow = 0;
		int counter = 0;
		
		for (int i = 0; i < 21; i++)
		{	
			
			if (!rowVisibility[i])
			{
				genreButtons[i].visible = true;
				genreButtons[i].x = counter * (buttonWidth + 6) + 6;
				genreButtons[i].y = histo_height + 50 +  (buttonRow * (buttonHeight + 6));
				genreButtons[i].draw(this);
				counter++;
			}
			else
				genreButtons[i].visible = false;
			
			// if many buttons, next row
			if (((counter + 1) * (buttonWidth + 6) + 6) > histo_width)
			{
				buttonRow++;
				counter = 0;
			}
		}
		
	}
	
	
	public void drawYearButtons()
	{
		
		// Set the font and its size (in units of pixels)
		textFont(font, 12);
		int counter = 0;
		int xcounter = 0;
		
		for (int i = 0; i < 7; i++)
		{	
			
			if (!columnVisibility[i])
			{
				yearButtons[i].visible = true;
				yearButtons[i].x = counter * (buttonWidth + 6) + 6;
				yearButtons[i].y = histo_height + 50 + (2 * (buttonHeight + 6));
				yearButtons[i].draw(this);
				counter++;

			}
			else
				yearButtons[i].visible = false;
		}
	}


	public void mouseDragged() {
		
		
	}
	

	
	// draw the bar buttons
	public void drawToggleButtons()
	{
		LabelButton b1 = new LabelButton(6 * (buttonWidth + 6) + 6,
									histo_height + 50 + (2 * (buttonHeight + 6)),
									buttonWidth, buttonHeight, "Earnings");
		b1.visible = histo[0][0].isBoxOfficeDisplayed();
		b1.draw(this);
		
		LabelButton b2 = new LabelButton(7 * (buttonWidth + 6) + 6,
				histo_height + 50 + (2 * (buttonHeight + 6)),
				buttonWidth, buttonHeight, "Count");
		
		b2.visible = histo[0][0].isCountDisplayed();
		b2.draw(this);
		
		LabelButton b3 = new LabelButton(8 * (buttonWidth + 6) + 6,
				histo_height + 50 + (2 * (buttonHeight + 6)),
				buttonWidth, buttonHeight, "Ratings");
		
		b3.visible = histo[0][0].isRatingsDisplayed();
		b3.draw(this);
	}
	
	
	
	// draw the text for presenting preferences
	public void drawPreferences()
	{
		String pref = "";
		
		
		for (int i = 0; i < 21; i++)      
			for (int j = 0; j < 7; j++)
			{
				if ((columnVisibility[j]) && (rowVisibility[i]))
					{
					//fill(0,128,227);	// blue = not seen
					//pref = String.valueOf(prefs[i][j][0]);
					//text(pref, histo[i][j].x + 10, histo[i][j].y + 20);
					
					fill(123,239,7);	// ligth green = seen + like
					pref = String.valueOf(prefs[i][j][1]);
					text(pref, histo[i][j].x + 20, histo[i][j].y + 20);
					
					fill(70,136,4);	// ligth green = seen + no opinion
					pref = String.valueOf(prefs[i][j][2]);
					text(pref, histo[i][j].x + 60, histo[i][j].y + 20);
					
					fill(225,13,13);	// red = seen + dislike
					
					pref = String.valueOf(prefs[i][j][3]);
					text(pref, histo[i][j].x + 100, histo[i][j].y + 20);
					}
				
			}
		
	}
	
	
	

	public void orderMovies() {


		
		System.out.println("initializing movies...");
		
		// initialize and index counter for each cell full of movies.
		int[][] index = new int[21][7];
		for (int i = 0; i < 21 ;i++) {
			for (int j = 0; j < 7 ;j++) {
				index[i][j] = 0;
			}
		}
		
		// count how many movies will be in each cell
		for (int i = 0; i < 21 ;i++) {
			for (int j = 0; j < 7 ;j++) {
				
				Iterator<Movie> iter = MovieDB.instance.movies.values().iterator();
				
				while (iter.hasNext()) {
					Movie m = iter.next();
					if (i<20) {
						if (m.genres.contains(Genre.values()[i]) && (m.year == 2000+j )) {
							movieCount[i][j]++;
						}
					} else {
						if (m.genres.isEmpty() && (m.year == 2000+j )) {
							movieCount[i][j]++;
						}
					}
				}

			}
		}
		
		for (int i = 0; i < 21 ;i++) {
			for (int j = 0; j < 7 ;j++) {
				ci[i][j] = new int[movieCount[i][j]];
			}
		}
		for (int i = 0; i < 21 ;i++) {
			for (int j = 0; j < 7 ;j++) {
				for (int k = 0; k < ci[i][j].length;k++) {
					ci[i][j][k] =0;
				}
			}
		}
		
		for (int i = 0; i < 21 ;i++) {
			for (int j = 0; j < 7 ;j++) {
				rc[i][j] = new int[movieCount[i][j]];
				gc[i][j] = new int[movieCount[i][j]];
				bc[i][j] = new int[movieCount[i][j]];
			}
		}
		
		for (int i = 0; i < 21 ;i++) {
			for (int j = 0; j < 7 ;j++) {
				for (int k = 0; k < rc[i][j].length;k++) {
					rc[i][j][k] = cs[0][0];
					gc[i][j][k] = cs[0][1];
					bc[i][j][k] = cs[0][2];
				}
			}
		}
		
		
		
		for (int i = 0; i < 21 ;i++) {
			for (int j = 0; j < 7 ;j++) {
				//int temp = ceil(sqrt(movieCount[i][j]));
				int temp = ceil(sq((float)Math.cbrt(movieCount[i][j])));
				
				if (temp > 44 )
					rowlength[i][j] = 44;
				else 
					rowlength[i][j] = temp;
			}
		}
		
		
		
		// initialize ordered array
		for (int i = 0; i < 21; i ++) {
			for (int j = 0; j < 7; j++) {
				ordered[i][j] = new Movie[movieCount[i][j]];
			}
		}
		
		// print array
		/*for (int i = 0; i < 21; i ++) {
			if (i<20) {
				System.out.print(Genre.values()[i] + ": ");
				for (int j = 0; j < 7; j++) {
					System.out.print(movieCount[i][j]+", ");
				}
				System.out.println();
			} else {
				System.out.print("Unknown" + ": ");
				for (int j = 0; j < 7; j++) {
					System.out.print(movieCount[i][j]+", ");
				}
				System.out.println();
			}
		}*/
//		Iterator<Movie> it =  MovieDB.instance.netflix.values().iterator();
		//System.out.println(it.next().netflixRating);
	//	Iterator<List<Oscar>> it2 = MovieDB.instance.oscars.values().iterator();

		// add unsorted items
		for (int i = 0; i < 21 ;i++) {
			for (int j = 0; j < 7 ;j++) {
				Iterator<Movie> iter = MovieDB.instance.movies.values().iterator();
				while (iter.hasNext()) {
					Movie m = iter.next();
					if ( i < 20 ) {
						if (m.genres.contains(Genre.values()[i]) && (m.year == 2000+j )) {
							ordered[i][j][index[i][j]] = m;
							index[i][j]++;
						}
					} else {
						if (m.genres.isEmpty() && (m.year == 2000+j)) {
							ordered[i][j][index[i][j]] = m;
							index[i][j]++;
						}
					}
				}

			}
		}
		
		
		System.out.println("sorting movies...");
	//	System.out.println(ordered[0][0][0].title + ", " + ordered[0][0][0].boxOfficeEarnings);
		// first sort movies by box office results
		//for (int k = 0; k < ordered[0][0].length; k++ ) {
		for (int i = 0; i < 21 ;i++) {
			for (int j = 0; j < 7 ;j++) {
				Arrays.sort(ordered[i][j], new MovieComparator());
			}
		}
		//System.out.println(ordered[0][0][0].title + ", " + ordered[0][0][0].boxOfficeEarnings );

		
		sorted = new Movie[21][7][];
		
		for (int i = 0; i < 21; i ++) {
			for (int j = 0; j < 7; j++) {
				sorted[i][j] = new Movie[movieCount[i][j]];
			}
		}
		
	
		
		for (int i = 0; i < 21; i ++) {
			for (int j = 0; j < 7; j++) {
				int rowWidth = rowlength[i][j];
				int colLength = 0;
				int leftover = 0;
				if ( rowWidth != 0) {
					colLength = sorted[i][j].length / rowWidth;
					leftover = sorted[i][j].length % rowWidth;
				}
				int orderedCount = 0;
				
				for (int k = 0; k < rowWidth; k++) {
					int substring = 0;
					if ( k < leftover) {
					    substring = colLength + 1;
					} else {
						substring = colLength;
					}
					
					Movie[] temp = new Movie[substring];
					
					for (int l = 0; l < temp.length; l++ ) {
						temp[l] = ordered[i][j][orderedCount];
						orderedCount++;
					}
					
					Arrays.sort(temp, new MovieRatingComparator());
					if (i==0 &&j==0) {
						for (int l =0; l < temp.length; l++) {
							System.out.print(temp[l].title + ", ");
						}
						System.out.println();
						for (int l =0; l < temp.length; l++) {
							System.out.print(temp[l].imdbRating + ", ");
						}
						System.out.println();
					}
					
					for (int l = 0; l < substring; l++ ) {
						sorted[i][j][(l*rowWidth) + k] = temp[l];
					}		
				}
			}
		}

		System.out.println("finished sorting movies");
		
		
		/*for (int i = 0; i < 21; i ++) {
			for (int j = 0; j < 7; j++) {
				float sum = 0;
				int count = 0;
				for (int k = 0; k < sorted[i][j].length; k++) {
					if (sorted[i][j][k].imdbRating > 0) {
						count++;
						sum += sorted[i][j][k].imdbRating;
					}
				}
				if (count != 0) {
					System.out.print(sum/((float)count) + ",");
				} else {
					System.out.print("0.0" + ",");
				}
			}
			System.out.println();
		}*/
	}
	

	

	// returns how many year buttons are pressed
	public int yearButtonPressed ()
	{
		int counter = 0;
		
		for (int i = 0; i < 7; i++)
			if (!columnVisibility[i])
				counter++;
		
		return counter;
	}
	

	// returns how many genre buttons are pressed
	public int genreButtonPressed ()
	{
		int counter = 0;
		
		for (int i = 0; i < 21; i++)
			if (!rowVisibility[i])
				counter++;
		
		return counter;
	}
	
}
	
	